#define _GNU_SOURCE
#include <sched.h>
#include <sys/time.h>

#include "libmdm.h"
#include "cms_log.h"
#include "cms_common.h"
#include "cms_mdm.h"
#include "task_utils.h"
#include "task_module.h"
#include "cms_event.h"
#include "cmsXml_object.h"
#include "cms_objFunc.h"
#include "task_common.h"


extern cmsTaskContext_t cmsTaskCtx;
extern cmsXmlCb_t *xmlShmCb;
extern const cmsObjFunc_t stats_objFuncTable[];
extern cmsEventLock_t *cmsEventLock;


void cmsTask_initEventLock(void){
	cmsEventLock = mmap(NULL, sizeof(*cmsEventLock), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);
	memset(cmsEventLock, 0, sizeof(*cmsEventLock));

	pthread_mutexattr_init(&cmsEventLock->mutexAttr);
	pthread_mutexattr_setpshared(&cmsEventLock->mutexAttr, PTHREAD_PROCESS_SHARED);
	pthread_mutex_init(&cmsEventLock->mutex, &cmsEventLock->mutexAttr);
}

void cmsTask_deInitEventLock(void){
	pthread_mutexattr_destroy(&cmsEventLock->mutexAttr);
	pthread_mutex_destroy(&cmsEventLock->mutex);
	munmap(cmsEventLock, sizeof(*cmsEventLock));
}


unsigned char a2x(const char c)
{
	switch(c)
	{
		case '0'...'9':
			return c-'0';
		case 'a'...'f':
			return 0xa + (c-'a');
		case 'A'...'F':
			return 0xa + (c-'A');
		default:
			return 0;
	}
	return 0;
}

void str2MAC(unsigned char *mac, char *str)
{
	int i = 0;
	for(i = 0; i< ETHER_ADDR_LEN; i++)
	{
		mac[i] = (a2x(str[i*3]) << 4) + (a2x(str[i*3 + 1]));
	}
}

void str2Gponsn(unsigned char *gponsn, char *str)
{
	int32_t i,j;
	char *p = NULL;
	char tmp[3] = {0};

	for(i = 0; i<4; i++)
	{
		gponsn[i] = str[i];
	}

	j = 4;
	for(i = 4; i < 12; i = i + 2, j++)
	{
		p = str;
		p = p + i;
		memset(tmp, 0, 3);
		strncpy(tmp, p, 2);
		gponsn[j] = (uint8_t)(strtoul(tmp, NULL, 16));
	}
}



uint64_t  GenerateIA(uint32_t highV, uint32_t lowV){
	uint64_t LowIaV = lowV, HighIaV = highV;

	return (((HighIaV << 32) & 0xFFFFFFFF00000000) | (LowIaV & 0x00000000FFFFFFFF));
}

objChgInfo_t *getObjInfoByIA(uint32_t objID , uint64_t objIA){
	objChgInfo_t *curChgObj = NULL;
	uint32_t objSize = 0;
	uint32_t iDepth = 0;
	int i = 0;

	iDepth =  cmsXmlGetIADepth(objIA);
	objSize = sizeof(objChgInfo_t) + (sizeof(uint32_t)*iDepth);

	curChgObj = (objChgInfo_t *)calloc(1, objSize);
	if(curChgObj == NULL){
		CMS_LOG(LL_ERROR, "malloc objChgInfo  fail.\n");
		return NULL;
	}

	curChgObj->objId = objID;
	curChgObj->iNodeObjId = objID;
	curChgObj->indexDepth = iDepth;
	for(i = 0; i < iDepth; i++){
		curChgObj->objIndexValue[i] = cmsXmlGetIAInfo(objIA, (i+1));
	}

	return curChgObj;
}


void signalHandler(int sig, siginfo_t *siginfo, void *notused){
	switch(sig){
		case SIGTERM:
		case SIGSEGV:
		case SIGHUP:
		case SIGKILL:
			fprintf(stderr, "cms task TERMINATING, pid %d, signal %d.\n", getpid(), sig);
			break;
		default:
			fprintf(stderr, "cms task receive signal %d.\n", sig);
			break;
	}
}

void cmsTask_registerSignal(void){
	struct sigaction sa;

	sa.sa_sigaction = signalHandler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = SA_SIGINFO;
	
	sigaction(SIGHUP, &sa, NULL);
	sigaction(SIGKILL, &sa, NULL);
	sigaction(SIGSEGV, &sa, NULL);
	sigaction(SIGTERM, &sa, NULL);
}

void cmsTask_dumpRegInfo(void){
	cms_eventListEntry_t *pCurEvent = NULL;
	cmsEventHandlerListEntry_t *pCurHandle = NULL;
	uint32_t eventCount = 0;
	
	cms_objectListEntry_t * pCurObjRegList = NULL;
	cms_objChgFuncList_t *pCurObjFuncList = NULL;
	uint32_t objCount = 0;

	/*dump reg event info*/
	CMS_LOG(LL_DEBUG, "*****************************event info*****************************\n");
	pCurEvent = cmsTaskCtx.eventList;
	while(pCurEvent){
		CMS_LOG(LL_DEBUG, "[%d]event id: %d\n", eventCount, pCurEvent->eventId);
		
		pCurHandle = pCurEvent->eventHandlerList;
		while(pCurHandle){
			CMS_LOG(LL_DEBUG, "eventhandle name: %s, handle prority: %d\n", 
				 pCurHandle->eventHandlerName, pCurHandle->priority);
			pCurHandle = pCurHandle->next;
		}
			
		eventCount++;
		pCurEvent = pCurEvent->next;
	}
	CMS_LOG(LL_DEBUG, "*****************************event info*****************************\n");
	CMS_LOG(LL_DEBUG, "\r\n\r\n");
	
	/*dump reg object info*/
	CMS_LOG(LL_DEBUG, "*****************************object info*****************************\n");
	pCurObjRegList = cmsTaskCtx.objRegList;
	while(pCurObjRegList){
		CMS_LOG(LL_DEBUG, "[%d]object: %d\n", objCount, pCurObjRegList->objectId);
		
		pCurObjFuncList = pCurObjRegList->objChgFuncList;
		while(pCurObjFuncList){
			CMS_LOG(LL_DEBUG, "objhandle name: %s, prority: %d, funcFlag: %d\n", 
				pCurObjFuncList->name, pCurObjFuncList->priority, pCurObjFuncList->funcFlag);
			pCurObjFuncList = pCurObjFuncList->next;
		}
			
		objCount++;
		pCurObjRegList = pCurObjRegList->next;
	}
	CMS_LOG(LL_DEBUG, "*****************************object info*****************************\n");
}


int cmsTask_regEventToCms(const cmsEventRegData_t *regEvent[]){
	cms_eventListEntry_t *curEvent = NULL, *newEvent = NULL;
	cmsEventHandlerListEntry_t *newEventHandler = NULL;
	cmsEventRegData_t **curRegEvent;
	uint32_t *curEventId;

	curRegEvent = (cmsEventRegData_t **)&(regEvent[0]);
	while(*curRegEvent){
		curEventId = &((*curRegEvent)->eventId[0]);

		while(*curEventId ){
			CMS_LOG(LL_DEBUG, "event id need to reigster %d, =======\n", *curEventId);
			/*check if exist in evet list*/
			curEvent = cmsTaskCtx.eventList;
			while(curEvent){
				if(curEvent->eventId == *curEventId)
					break;
				curEvent = curEvent->next;
			}

			/*if not exist, alloc new event*/
			if(!curEvent){
				newEvent = (cms_eventListEntry_t *)calloc(1, sizeof(cms_eventListEntry_t));
				if(newEvent == NULL)
					return -1;

				newEvent->eventId = *curEventId;
			
				INSERT_NODE(cmsTaskCtx.eventList, newEvent);
				curEvent = newEvent;
			}

			/*new event handler & hook to the event*/
			newEventHandler = (cmsEventHandlerListEntry_t *)calloc(1, sizeof(cmsEventHandlerListEntry_t));
			newEventHandler->eventHandlerName = (*curRegEvent)->name;
			newEventHandler->priority = (*curRegEvent)->priority;
			newEventHandler->handler = (*curRegEvent)->func;
			INSERT_NODE_BY_PRIORITY(curEvent->eventHandlerList, newEventHandler);
			
			curEventId++;
		}
		curRegEvent++;
	}

	return 0;
}

int cmsTask_regObjectToCms(const cmsConfigRegData_t *regObject[]){
	cms_objectListEntry_t *curObj = NULL, *newObj = NULL;
	cms_objChgFuncList_t *newConfigFunc = NULL;
	cmsConfigRegData_t **curRegObj;
	uint32_t tmpFuncFlag;
	uint32_t *curObjId, tmpObjId = 0;

	curRegObj = (cmsConfigRegData_t **)&(regObject[0]);
	while(*curRegObj){
		
		curObjId = &((*curRegObj)->objectId[0]);
		while(*curObjId){

			/*check obj if recursive*/
			tmpFuncFlag = 0;
			if(*curObjId & CMS_TASKMODULE_FUNC_RECURSIVE){
				tmpFuncFlag = CMS_OBJECT_RECURSIVE_FLAG;
				tmpObjId = *curObjId & (~CMS_TASKMODULE_FUNC_RECURSIVE);
			}else{
				tmpObjId = *curObjId;
			}
			
			/*check if exist in object list*/
			curObj = cmsTask_getObjectById(tmpObjId);
			/*if not exist, alloc new event*/
			if(!curObj){
				newObj = (cms_objectListEntry_t *)calloc(1, sizeof(cms_objectListEntry_t));
				if(newObj == NULL)
					return -1;

				newObj->objectId = tmpObjId;
				INSERT_NODE(cmsTaskCtx.objRegList, newObj);
				curObj = newObj;
			}

			/*configLoader list check & insert*/
			newConfigFunc = curObj->objChgFuncList;
			while(newConfigFunc){
				if(newConfigFunc->confgLoader == (*curRegObj)->func)
					break;

				newConfigFunc = newConfigFunc->next;
			}
			if(!newConfigFunc){
				newConfigFunc = (cms_objChgFuncList_t *)calloc(1, sizeof(cms_objChgFuncList_t));
				newConfigFunc->confgLoader = (*curRegObj)->func;
				//newConfigFunc->execFlag = 0;
				newConfigFunc->funcFlag = tmpFuncFlag;
				newConfigFunc->name = (*curRegObj)->name;
				newConfigFunc->priority = (*curRegObj)->priority;

				INSERT_NODE_BY_PRIORITY(curObj->objChgFuncList, newConfigFunc);
			}
			
			curObjId++;
		}
		curRegObj++;
	}

	return 0;
}

int cmsTask_regCmdServiceToCms(const cmsTask_cmdServiceRegData_t *regCmd[]){
	cmsTask_cmdList_t *pCurCmdService = NULL, *pNewCmdService = NULL;
	cmsTask_cmdHandlerList_t *pNewCmdHandler = NULL;
	cmsTask_cmdServiceRegData_t **curRegCmd_pp;
	uint32_t *cmdCode;

	curRegCmd_pp = (cmsTask_cmdServiceRegData_t **)&(regCmd[0]);
	while(*curRegCmd_pp){
		cmdCode = (*curRegCmd_pp)->cmdServiceCode;
		while(*cmdCode){
			pCurCmdService = cmsTaskCtx.cmdServiceList;
			while(pCurCmdService){
				if(pCurCmdService->cmd == *cmdCode)
					break;
				pCurCmdService = pCurCmdService->next;
			}

			if(pCurCmdService == NULL){
				pNewCmdService = (cmsTask_cmdList_t *)calloc(1, sizeof(cmsTask_cmdList_t));
				pNewCmdService->cmd = *cmdCode;
				INSERT_NODE(cmsTaskCtx.cmdServiceList,pNewCmdService);

				pNewCmdHandler = (cmsTask_cmdHandlerList_t *)calloc(1, sizeof(cmsTask_cmdHandlerList_t));
				pNewCmdHandler->cmdHandlerName = (*curRegCmd_pp)->name;
				pNewCmdHandler->handler = (*curRegCmd_pp)->func;
				pNewCmdHandler->priority = (*curRegCmd_pp)->priority;
				INSERT_NODE_BY_PRIORITY(pNewCmdService->cmdHandlerList, pNewCmdHandler);
			}else{
				return -1;
			}
			
			cmdCode++;
		}
		
		curRegCmd_pp++;
	}
	
	return 0;
}

cms_eventListEntry_t *cmsTask_getEventById(uint32_t eventId){
	cms_eventListEntry_t *pCurEventList = cmsTaskCtx.eventList;

	while(pCurEventList != NULL){
		if(eventId == pCurEventList->eventId)
			return pCurEventList;
		
		pCurEventList = pCurEventList->next;
	}

	return NULL;
}

cms_objectListEntry_t *cmsTask_getObjectById(uint32_t objId){
	cms_objectListEntry_t *pCurObj = cmsTaskCtx.objRegList;

	while(pCurObj){
		if(objId == pCurObj->objectId)
			return pCurObj;

		pCurObj = pCurObj->next;
	}
	
	return NULL;
}


int cmsTask_handleEvent(uint32_t eventId, uint32_t typeSizeOfValue, void *eventValue){
	cms_eventListEntry_t *pCurEvent = NULL;
	cmsEventHandlerListEntry_t *pCurEventHandler = NULL;
	
	pCurEvent = cmsTask_getEventById(eventId);
	if(pCurEvent){
		pCurEventHandler = pCurEvent->eventHandlerList;
		while(pCurEventHandler){
			if(pCurEventHandler->priority != CMS_NOTIFY_PRORITY_INTURRUPT_HANDLER){
				//CMS_SYSLOG(LOG_DEBUG, "cms_task start event handle action(eventId %d, funcName %s).", eventId, pCurEventHandler->eventHandlerName);
				pCurEventHandler->handler(eventId, typeSizeOfValue, eventValue);
				//CMS_SYSLOG(LOG_DEBUG, "cms_task end event handle action(eventId %d, funcName %s).", eventId, pCurEventHandler->eventHandlerName);
			}
			
			pCurEventHandler = pCurEventHandler->next;
		}
	}else{
		CMS_LOG(LL_ERROR, "eventid %d, find eventlist fail.\n",eventId);
	}
		
	return 0;
}

int cmsTask_collectObjChg(objectChgData_t *objData){
	cmsObjChgList_t *newObjChg = NULL;
	uint32_t objLen;
	uint32_t objOPflag;

	/*init object change structure*/
	newObjChg = (cmsObjChgList_t *)calloc(1, sizeof(cmsObjChgList_t));
	newObjChg->objId = objData->objectId;
	newObjChg->objIA = objData->indexArry;
	newObjChg->realId = objData->realId;
	newObjChg->oldData = NULL;
	newObjChg->newData = NULL;
	objLen = (objData->objectSize) & CMS_DB_OBJ_SIZE_MASK;
	objOPflag = (objData->objectSize) & CMS_DB_FLAG_MASK;
	
	/*copy object data*/
	if(objOPflag == CMS_DB_SET_OBJECT){
		newObjChg->oldData = malloc(objLen);
		newObjChg->newData = malloc(objLen);
		newObjChg->objAction = CMS_OBJ_SET;
		
		memcpy(newObjChg->oldData, objData->objValue, objLen);
		memcpy(newObjChg->newData, ((uint8_t *)objData->objValue + objLen), objLen);
	}else if(objOPflag == CMS_DB_ADD_OBJECT){
		newObjChg->oldData = NULL;
		newObjChg->newData = malloc(objLen);
		newObjChg->objAction = CMS_OBJ_ADD;
		
		memcpy(newObjChg->newData, ((uint8_t *)objData->objValue + objLen), objLen);
	}else if(objOPflag == CMS_DB_DEL_OBJECT){
		newObjChg->oldData = objData->objValue;
		newObjChg->newData = NULL;
		newObjChg->oldData = malloc(objLen);
		newObjChg->objAction = CMS_OBJ_DEL;

		memcpy(newObjChg->oldData, objData->objValue, objLen);
	}else{
		newObjChg->oldData = NULL;
		newObjChg->newData = NULL;
		newObjChg->objAction = CMS_OBJ_UNKNOWN;
	}

	CMS_LOG(LL_INFO,"objchg handle -- objID %d, objIA %lx, action %d====================\n", objData->objectId, objData->indexArry, newObjChg->objAction);

	INSERT_NODE(cmsTaskCtx.objChgList, newObjChg);
	
	return 0;
}

uint32_t *cmsTask_getParentObjectIdArrayByOID(cmsXmlCb_t *xmlShmCb, int objId, uint64_t IA, int *count, uint32_t *strbuf ){
	objectNode_t *node = NULL, *pNode = NULL;
	void *object = NULL;
	cmsoffset_t parent = 0;
	uint32_t i = 0, eid;
	
	memset(strbuf, 0, DATA_SIZE);
	
	eid = objId;
	strbuf[i++] = eid;
	(*count)++;
	
	XML_LOCK(&xmlShmCb->cmsMutex->lock);
	/*get node*/
	object = cmsXml_GetObjectByOID(xmlShmCb, objId, IA, NULL_IF_NOT_EXISTED);
	if(object){
		node = xmlShmCb->objectNode;
		parent = node->parent;
	}else{/*set IA to 0, to get proto type object*/	
		object = cmsXml_GetObjectByOID(xmlShmCb, objId, 0, NULL_IF_NOT_EXISTED);
		if(object){
			node = xmlShmCb->objectNode;
			parent = node->parent;
		}
	}

	/*get parent node*/
	while((pNode = cmsXmlGetObjRealAddr(xmlShmCb, parent)) != NULL){
		eid = cmsXml_GetOIDByTable(pNode->object);
		strbuf[i++] = eid;
		(*count)++;

		parent = pNode->parent;
	}
	XML_UNLOCK(&xmlShmCb->cmsMutex->lock);

	for(i = 0; i < (*count)/2; i++){
		eid = strbuf[i];
		strbuf[i] = strbuf[(*count) -i-1];
		strbuf[(*count) -i-1] = eid;
	}
	
	return strbuf;
}

/*handle task module with one OID info*/
int cmsTask_handleConfigEvent(event_t *event, cms_configChgArg_t *configArg){
	cms_objectListEntry_t *curObj = NULL;
	cms_objChgFuncList_t *curObjFunc = NULL;
	uint32_t eventNum;
	uint32_t objId;
	int i = 0;
	//cmsTask_dumpRegInfo();

	eventNum = event->eventCount;
	for(i = 0; i < eventNum; i++){
		objId = event->eventId[i];
		CMS_LOG(LL_DEBUG, "current objid is %d===========\n", objId);
		curObj = cmsTask_getObjectById(objId);
		if(curObj){
			
			curObjFunc = curObj->objChgFuncList;
			while(curObjFunc){
				CMS_LOG(LL_DEBUG, "objId %d, handler name %s, prority %d, recurFlag is %d\n", objId, 
					curObjFunc->name, curObjFunc->priority, curObjFunc->funcFlag);
				if((curObjFunc->funcFlag & CMS_OBJECT_RECURSIVE_FLAG) || (i == (eventNum - 1))){
					CMS_LOG(LL_DEBUG, "match object id, handle=============\n");
				//	CMS_SYSLOG(LOG_DEBUG, "cms_task start obj chg handle, objid %u, funcName %s, prority %u, funcFlag %u.", 
				//		objId, curObjFunc->name, curObjFunc->priority, curObjFunc->funcFlag);
					curObjFunc->confgLoader(configArg);
				//	CMS_SYSLOG(LOG_DEBUG, "cms_task end obj chg handle, objid %u, funcName %s, prority %u, funcFlag %u.", 
				//		objId, curObjFunc->name, curObjFunc->priority, curObjFunc->funcFlag);
				}

				curObjFunc = curObjFunc->next;
			}
		}
	}

	return 0;
}

/*handle task module with mutil obj info*/
int cmsTask_serachObjFunc(cms_configChgArg_t *configArgList)
{
	cms_objectListEntry_t *curObj = NULL;
	cms_objChgFuncList_t *curObjFunc = NULL;
	cms_configChgArg_t *curConfigArg = configArgList, *tmpConfigArg = NULL, *newConfigArg = NULL;
	cms_multiObjTask_t *pMutilObjTaskHead = NULL, *pCurMutiObjTask = NULL,  *pNewMutiObjTask = NULL, *tmpTask = NULL;
	uint32_t objDepth;
	uint32_t objId;
	//int len = 0;
	int i = 0;

	/*check object change list*/
	if(curConfigArg == NULL)
		return -1;

	/*find the func which care changed obj*/
	while(curConfigArg){
		objDepth = curConfigArg->event->eventCount;
		for(i = 0; i < objDepth; i++){
			objId = curConfigArg->event->eventId[i];
			curObj = cmsTask_getObjectById(objId);
			if(curObj){
				curObjFunc = curObj->objChgFuncList;
				while(curObjFunc){

					if((curObjFunc->funcFlag & CMS_OBJECT_RECURSIVE_FLAG) || (i == (objDepth - 1))){
						if(pMutilObjTaskHead == NULL){
							pMutilObjTaskHead = (cms_multiObjTask_t *)calloc(1, sizeof(cms_multiObjTask_t));
							if(pMutilObjTaskHead == NULL)
								return -1;

							pMutilObjTaskHead->taskName = curObjFunc->name;
							pMutilObjTaskHead->taskFunc = curObjFunc->confgLoader;
							pMutilObjTaskHead->objChgArgList = (cms_configChgArg_t *)calloc(1, sizeof(cms_configChgArg_t));
							if(pMutilObjTaskHead->objChgArgList == NULL)
								goto exit;
							pMutilObjTaskHead->objChgArgList->event = curConfigArg->event;
							pMutilObjTaskHead->objChgArgList->eventContent = curConfigArg->eventContent;
							pMutilObjTaskHead->objChgArgList->oldObjData = curConfigArg->oldObjData;
							pMutilObjTaskHead->objChgArgList->objAction = curConfigArg->objAction;
						}else{
							pCurMutiObjTask = pMutilObjTaskHead;
							while(pCurMutiObjTask){
								if((strcmp(pCurMutiObjTask->taskName, curObjFunc->name) == 0) && (pCurMutiObjTask->taskFunc == curObjFunc->confgLoader)){
									break;
								}
								pCurMutiObjTask = pCurMutiObjTask->next;
							}
							if(pCurMutiObjTask){/*found*/
								newConfigArg = (cms_configChgArg_t *)calloc(1, sizeof(cms_configChgArg_t));
								if(newConfigArg == NULL)
									goto exit;
								newConfigArg->event = curConfigArg->event;
								newConfigArg->eventContent = curConfigArg->eventContent;
								newConfigArg->oldObjData = curConfigArg->oldObjData;
								newConfigArg->objAction = curConfigArg->objAction;
								if(pCurMutiObjTask->objChgArgList == NULL)
									pCurMutiObjTask->objChgArgList = newConfigArg;
								else{
									tmpConfigArg = pCurMutiObjTask->objChgArgList;
									while(tmpConfigArg->next){
										tmpConfigArg = tmpConfigArg->next;
									}
									tmpConfigArg->next = newConfigArg;
									newConfigArg->prev = tmpConfigArg;
									newConfigArg->next = NULL;
								}
									
							}else{/*not found*/
								pNewMutiObjTask = (cms_multiObjTask_t *)calloc(1, sizeof(cms_multiObjTask_t));
								if(pNewMutiObjTask == NULL){
									goto exit;
								}

								pNewMutiObjTask->taskName = curObjFunc->name;
								pNewMutiObjTask->taskFunc = curObjFunc->confgLoader;
								pNewMutiObjTask->objChgArgList = (cms_configChgArg_t *)calloc(1, sizeof(cms_configChgArg_t));
								if(pNewMutiObjTask->objChgArgList == NULL)
									goto exit;
								pNewMutiObjTask->objChgArgList->event = curConfigArg->event;
								pNewMutiObjTask->objChgArgList->eventContent = curConfigArg->eventContent;
								pNewMutiObjTask->objChgArgList->oldObjData = curConfigArg->oldObjData;
								pNewMutiObjTask->objChgArgList->objAction = curConfigArg->objAction;

								/*add new mutiObjList node to list tail*/
								pCurMutiObjTask = pMutilObjTaskHead;
								while(pCurMutiObjTask->next){
									pCurMutiObjTask = pCurMutiObjTask->next;
								}
								pCurMutiObjTask->next = pNewMutiObjTask;
								pNewMutiObjTask->prev = pCurMutiObjTask;
								pNewMutiObjTask->next = NULL;
								
							}
						}
					}

					curObjFunc = curObjFunc->next;
				}
			}
		}
		
		curConfigArg = curConfigArg->next;
	}

	
	pCurMutiObjTask = pMutilObjTaskHead;
	while(pCurMutiObjTask){
		if(pCurMutiObjTask->objChgArgList != NULL){
		//	CMS_SYSLOG(LOG_DEBUG, "cms_task start obj chg handle, funcName %s.", pCurMutiObjTask->taskName);
			pCurMutiObjTask->taskFunc(pCurMutiObjTask->objChgArgList);
		//	CMS_SYSLOG(LOG_DEBUG, "cms_task end obj chg handle, funcName %s.", pCurMutiObjTask->taskName);
		}
		
		pCurMutiObjTask = pCurMutiObjTask->next;
	}
	
exit:
	pCurMutiObjTask = pMutilObjTaskHead;
	while(pCurMutiObjTask){
		if(pCurMutiObjTask->objChgArgList != NULL){
			curConfigArg = pCurMutiObjTask->objChgArgList;
			while(curConfigArg){
				tmpConfigArg = curConfigArg;
				curConfigArg = curConfigArg->next;

				DELETE_NODE(pCurMutiObjTask->objChgArgList, tmpConfigArg);
			}
		}
		tmpTask = pCurMutiObjTask;
		
		pCurMutiObjTask = pCurMutiObjTask->next;
		DELETE_NODE(pMutilObjTaskHead, tmpTask);
	}


	return 0;
}

int cmsTask_handleObjChg(cmsObjChgList_t *objChgList, cmsBoolean isMutliObj){
	cmsObjChgList_t *curObjPtr = NULL, *tmpObjPtr = NULL;
	cms_configChgArg_t *newConfigArg = NULL, *configArgHead = NULL,* tmpConfigArg = NULL;
	uint32_t strbuf[DATA_SIZE];
	int parentCount = 0;
	uint32_t *objIdArry;
	event_t *event;
	int i =0;
	
	curObjPtr = objChgList;
	while(curObjPtr){

		parentCount = 0;
		i = 0;

		/*mallco event structure, put object &it's parent to event struct, and put obj & IA to structure*/
		objIdArry = cmsTask_getParentObjectIdArrayByOID(xmlShmCb, curObjPtr->objId, curObjPtr->objIA, &parentCount, strbuf);
		CMS_LOG(LL_DEBUG, "get parent num is %d\n", parentCount);

		event = malloc(sizeof(uint32_t) *(parentCount+4));
		memset(event, 0, sizeof(uint32_t) *(parentCount+4));
		event->eventCount = parentCount;
		event->eventId[parentCount] = (uint32_t)(curObjPtr->objIA >> 32);
		event->eventId[parentCount + 1] = (uint32_t)(curObjPtr->objIA);

		for(i = 0; i < parentCount; i++){
			event->eventId[i] = objIdArry[i];
			CMS_LOG(LL_DEBUG, "parent object id %d==================\n", event->eventId[i]);
		}
		CMS_LOG(LL_DEBUG, "parentCount %d, OID %d, obj IA is %"PRIx64"\n",parentCount, event->eventId[parentCount-1], GenerateIA(event->eventId[parentCount], event->eventId[parentCount + 1]));

		/*config event parameter*/
		newConfigArg = (cms_configChgArg_t *)calloc(1, sizeof(cms_configChgArg_t));
		newConfigArg->event = event;
		newConfigArg->oldObjData = curObjPtr->oldData;
		newConfigArg->objAction = curObjPtr->objAction;

		/*only support one obj chg*/
		if(isMutliObj == FALSE){
			/*handle changed obj, set falg to 1*/
			cmsTask_handleConfigEvent(event, newConfigArg);

			safe_free(newConfigArg);
			safe_free(event);
		}else{ /*support multi obj chg*/
			if(configArgHead == NULL)
				configArgHead = newConfigArg;
			else{
				tmpConfigArg = configArgHead;
				while(tmpConfigArg->next){
					tmpConfigArg = tmpConfigArg->next;
				}
				tmpConfigArg->next = newConfigArg;
				newConfigArg->prev = tmpConfigArg;
				newConfigArg->next = NULL;
			}
		}
		curObjPtr = curObjPtr->next;
	}
	

	if(isMutliObj == TRUE){ /*support multi obj chg*/
		/*handle changed obj*/
		cmsTask_serachObjFunc(configArgHead);
		
		/*free obj arg list*/
		newConfigArg = configArgHead;
		while(newConfigArg){
			tmpConfigArg = newConfigArg;
			newConfigArg = newConfigArg->next;

			safe_free(tmpConfigArg->event);
			DELETE_NODE(configArgHead, tmpConfigArg);
		}
	}

//exit:	
	/*free obj change list*/
	curObjPtr = cmsTaskCtx.objChgList;
	while(curObjPtr){

		tmpObjPtr = curObjPtr;
		curObjPtr = curObjPtr->next;

		safe_free(tmpObjPtr->oldData);
		safe_free(tmpObjPtr->newData);
		DELETE_NODE(cmsTaskCtx.objChgList,tmpObjPtr);

	}
	cmsTaskCtx.objChgList = NULL;

	return 0;
}

int cmsTask_handleCmdService(cmdService_t *cmdService){
	cmsTask_cmdList_t *pCurCmdService = NULL;
	cmsTask_cmdHandlerList_t *pCurCmdHandler = NULL;
	uint32_t cmdCode;
	value_t *cmdContent;
	int ret = -1;

	cmdCode = cmdService->cmdCode;
	cmdContent = (value_t *)&(cmdService->typeSizeOfContent);

	/*find cmd code in list*/
	pCurCmdService = cmsTaskCtx.cmdServiceList;
	while(pCurCmdService){
		if(pCurCmdService->cmd == cmdCode)
			break;
		pCurCmdService = pCurCmdService->next;
	}

	/*if find, handle*/
	if(pCurCmdService){
		pCurCmdHandler = pCurCmdService->cmdHandlerList;
		while(pCurCmdHandler){
			ret = pCurCmdHandler->handler(cmdCode, cmdContent);
			if(ret == -1){
				return -1;
			}
			pCurCmdHandler = pCurCmdHandler->next;
		}
	}else{
		return -1;
	}

	return 0;
}

int cmsTask_objectStats(uint32_t OID, uint64_t IA){
	int ret = -1;

	if(stats_objFuncTable[OID].objFuncPtr == NULL){
		CMS_LOG(LL_ERROR, "The OID %d doesn't support stats func.\n", OID);
		return ret;
	}

	/* for WiFi node, need check WifiNum */
	if (OID >= OID_InternetGatewayDevice_WiFi &&
		OID <= OID_InternetGatewayDevice_WiFi_X_GC_WiFi_End) {
#if 0
		if (libgc_sys_getWifiNum() == 0) {
			return 0;
		}
#endif
	}

	ret = stats_objFuncTable[OID].objFuncPtr(IA);

	return ret;
}


/*clean up some config which need config by OLT*/
void cmsTask_cleanUp(void)
{
	/*
	* clean up wan object which config by OAM/OMCI
	*/
	void *object = NULL;
	cmsObj_InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANPPPConnection_i_t *wanPppConn = NULL;
	cmsObj_InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANIPConnection_i_t *wanIpConn = NULL;
	cmsObj_InternetGatewayDevice_LANDevice_i_LANEthernetInterfaceConfig_i_X_GC_ONU_MULTICAST_VLAN_i_t *vlancfg = NULL;
	uint32_t objId = 0;
	uint64_t objIA = 0;
	uint32_t maxWanIndex = InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_Max;
	int iLanDev;
	int iLanEthConf;
	int index = 0;

	/* check wan.*/
	/* This code has no use now, the 'if(0)' branch will never enter. But leave it here as an example. */
	if(0){
		int iWDev = 0;
		int iWCDev = 0;
		int ipIndex = 0;
		int pppIndex = 0;
		uint32_t maxWANConnectionDev = InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_Max;
		uint32_t maxWANIPConnection = InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANIPConnection_i_Max;
		uint32_t maxWANPPPConnection = InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANPPPConnection_i_Max;
		/*check ppp*/
		for(iWDev = 0; iWDev < maxWanIndex; iWDev++){
			for(iWCDev = 0; iWCDev < maxWANConnectionDev; iWCDev++){
				for(pppIndex = 0; pppIndex < maxWANPPPConnection; pppIndex++){
					objId = OID_InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANPPPConnection_i;
					objIA = cmsXmlConstructIAValue(3,"%d,%d,%d",iWDev+1,iWCDev+1,ipIndex+1);
					object = cmsXml_GetObjectByOID(xmlShmCb, objId, objIA, NULL_IF_NOT_EXISTED);
					if(object != NULL){
						wanPppConn = (cmsObj_InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANPPPConnection_i_t *)object;
						if(wanPppConn->X_GC_OLTCreateFlag == 1){
							cmsXmlDelObjByOID(xmlShmCb, objId, objIA);
						}
					}
				}
			}
		}

		/*check ipoe*/
		for(iWDev = 0; iWDev < maxWanIndex; iWDev++){
			for(iWCDev = 0; iWCDev < maxWANConnectionDev; iWCDev++){
				for(ipIndex = 0; ipIndex < maxWANIPConnection; ipIndex++){
					objId = OID_InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANIPConnection_i;
					objIA = cmsXmlConstructIAValue(3,"%d,%d,%d",iWDev+1,iWCDev+1,ipIndex+1);
					object = cmsXml_GetObjectByOID(xmlShmCb, objId, objIA, NULL_IF_NOT_EXISTED);
					if(object != NULL){
						wanIpConn = (cmsObj_InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANIPConnection_i_t *)object;
						if(wanIpConn->X_GC_OLTCreateFlag == 1){
							cmsXmlDelObjByOID(xmlShmCb, objId, objIA);
						}
					}
				}
			}
		}
	}

	/*check igmpvlan*/
	for (iLanDev = 1; iLanDev <= InternetGatewayDevice_LANDevice_i_Max; iLanDev++) {	  
		for (iLanEthConf = 1; iLanEthConf <= InternetGatewayDevice_LANDevice_i_LANEthernetInterfaceConfig_i_Max; iLanEthConf++) {
			objId = OID_InternetGatewayDevice_LANDevice_i_LANEthernetInterfaceConfig_i;
			objIA = cmsXmlConstructIAValue(2,"%d,%d",iLanDev,iLanEthConf);
			object = cmsXml_GetObjectByOID(xmlShmCb, objId, objIA, NULL_IF_NOT_EXISTED);
			if(object){
				for(index = 1; index <= InternetGatewayDevice_LANDevice_i_LANEthernetInterfaceConfig_i_X_GC_ONU_MULTICAST_VLAN_i_Max; index++){
					objId = OID_InternetGatewayDevice_LANDevice_i_LANEthernetInterfaceConfig_i_X_GC_ONU_MULTICAST_VLAN_i;
					objIA = cmsXmlConstructIAValue(3,"%d,%d,%d",iLanDev,iLanEthConf,index);
					object = cmsXml_GetObjectByOID(xmlShmCb, objId, objIA, NULL_IF_NOT_EXISTED);
					if(object){
						vlancfg = (cmsObj_InternetGatewayDevice_LANDevice_i_LANEthernetInterfaceConfig_i_X_GC_ONU_MULTICAST_VLAN_i_t *)object;
						if(vlancfg->OLTSet)
							cmsXmlDelObjByOID(xmlShmCb, objId, objIA);
					}
				}
			}
		}
	}

	return;
}

#ifdef GC_XML_UPDATE_SUPPORT
void cmsTask_updateXml(void)
{
	const char *updateFile = "/usr/config/cmsUpdateFile";
	cmsObj_InternetGatewayDevice_DeviceInfo_t *pDeviceInfo = NULL;
	char cmdStr[64] = {0};
	char curSoftVer[128] = {0};
	
	pDeviceInfo = cmsXmlGetObjectByOID(xmlShmCb, OID_InternetGatewayDevice_DeviceInfo, 0);
	if(pDeviceInfo == NULL){
		CMS_LOG(LL_ERROR, "Fail to get device info node of XML.");
		return;
	}
#ifdef GC_APPS_SWVERSION_FROM_DEFAULT_XML
		defXmlShmCb =  XMLSHM_DEFAULT_INIT();
		if(defXmlShmCb == NULL){
			CMS_LOG(LL_ERROR, "Fail to init def xmlshmcb.");
			return;
		}
		cmsObj_InternetGatewayDevice_DeviceInfo_t *pDefDeviceInfo = cmsXml_GetObjectByOID(defXmlShmCb, OID_InternetGatewayDevice_DeviceInfo, 0);
		if(pDefDeviceInfo == NULL){
			CMS_LOG(LL_ERROR, "Fail to get def device info node of XML.");
			return;
		}
		strcpy(curSoftVer, pDefDeviceInfo->SoftwareVersion);
		XMLSHM_DEFAULT_DEINIT(defXmlShmCb);
#else
		libgc_sys_getFwVersion(curSoftVer);
#endif
	if(strcmp(pDeviceInfo->SoftwareVersion, curSoftVer) == 0)
		return;

	if(access(updateFile, F_OK) == 0){
		sprintf(cmdStr, sizeof(cmdStr), "cmc -f %s", updateFile);
		cms_do_cmd(cmdStr);
		cmsBoolean updateFlag = 1;
		cmsXmlSetOneParameterByOID(xmlShmCb, OID_InternetGatewayDevice_X_GC_UPDATEXML, 0, "UpdateFlag", PARAMETER_TYPE_BOOLEAN, &updateFlag);
		cmsXmlSave(xmlShmCb);
	}
	
	return;
}
#endif

void cmsTask_moduleInit(void){
	cmsTask_regInit_sample();
}

void *cmsTask_configLoadSecHandle(void *arg){
	int mainCpuNo = *(int *)arg;
	int cpuTotalNum = sysconf(_SC_NPROCESSORS_CONF);

	CMS_LOG(LL_NOTICE, "cpuTotalNum %d, main thread cpu no %d.", cpuTotalNum, mainCpuNo);
	if(cpuTotalNum > 1 && mainCpuNo >= 0){
		for(int cpuIndex = 0; cpuIndex < cpuTotalNum; cpuIndex++){
			if(cpuIndex != mainCpuNo){
				cpu_set_t mask;
				__CPU_ZERO_S(sizeof(mask), &mask);
				__CPU_SET_S(cpuIndex, sizeof(mask), &mask);
				if(sched_setaffinity(0, sizeof(mask), &mask) == -1){
					CMS_LOG(LL_WARNING, "sec config load thread bind to cpu %d fail.", cpuIndex);
				}else{
					break;
				}
			}
		}
	}
	CMS_LOG(LL_NOTICE, "task sec run in cpu %d, main cpu no %d, cpuTotalNum %d.", 
			sched_getcpu(), mainCpuNo, cpuTotalNum);
	
	struct timeval tv; 
	gettimeofday(&tv, NULL);
	CMS_LOG(LL_PRINT, "#####configLoadSecHandle start[%lu.%lu]",tv.tv_sec, tv.tv_usec/1000);
	
    //===================start===================

    //====================end====================

	gettimeofday(&tv, NULL);
	CMS_LOG(LL_PRINT, "#####configLoadSecHandle end[%lu.%lu]",tv.tv_sec, tv.tv_usec/1000);

	/*clean late reponse msg, such as timeout status, before thread exit*/
	cms_cleanZombieMsg();
	return (void *)NULL;
}

void cmsTask_configLoadHandle(void){
	struct timeval tv; 
	gettimeofday(&tv, NULL);
	CMS_LOG(LL_PRINT, "#####configLoadHandle start[%lu.%lu]",tv.tv_sec, tv.tv_usec/1000);

    //===================start===================
    objectSample_handler(NULL);
    //====================end====================

	gettimeofday(&tv, NULL);
	CMS_LOG(LL_PRINT, "#####configLoadHandle end[%lu.%lu]",tv.tv_sec, tv.tv_usec/1000);
}

/*pre-config by mrd or hw before db & task prog boot*/
void cmsTask_preConfig(void)
{
	//char DefLanguage[32] = {0};
	uint8_t GeNum=0;
	uint8_t FeNum=0;
	uint8_t TwoGeNum=0;
	uint8_t TenGeNum=0;	
	uint8_t WifiNum=0;
	uint8_t UsbNum=0;
	uint8_t deviceType = 1;
	void *objData_wifi = NULL;
	cmsoffset_t objOff;
	paraValueSettingList_t *paralist;
	void *lan_object = NULL;

	//libgc_sys_getLanguage(DefLanguage);
	//cmsXmlSetOneParameterByObjPath(xmlShmCb, "InternetGatewayDevice.X_GC_EXT.X_GC_MultiLanguage", "DefaultLanguage", PARAMETER_TYPE_STRING, DefLanguage);

	/*Get the Ge Num and Fe Num from the mrd file.*/
#if 0
	GeNum=libgc_sys_getGeEthNum();
	FeNum=libgc_sys_getFeEthNum();
	TwoGeNum=libgc_sys_get2GeEthNum();
	TenGeNum=libgc_sys_get10GeEthNum();
	WifiNum=libgc_sys_getWifiNum();
	UsbNum=libgc_sys_getUsbNum();
	deviceType = libgc_sys_getDeviceType();
#endif

#ifdef GC_SUPPORT_WSD_ETHER_ROUTER
	uint8_t iswan = 0;
	int i;
	for(i = 0; i < GeNum; i++){
        if(libgc_switchApi_portGetWanPort(i, &iswan) == 0){
            if(iswan == 1){
				GeNum = GeNum - 1;
				break;
			}
        }
    }
#endif
	lan_object = cmsXml_GetObjectByOID(xmlShmCb, OID_InternetGatewayDevice_LANDevice_i,cmsXmlConstructIAValue(1,"1"),NULL_IF_NOT_EXISTED); 
	if(lan_object != NULL){
		objOff = cmsXmlGetPtrOffset(xmlShmCb, lan_object);
		paralist = newParameterList();
		if (paralist != NULL) {
			 setParameterToList(paralist, "GeNum", PARAMETER_TYPE_UINT8, &GeNum);
			 setParameterToList(paralist, "FeNum", PARAMETER_TYPE_UINT8, &FeNum);
			 setParameterToList(paralist, "TwoGeNum", PARAMETER_TYPE_UINT8, &TwoGeNum);
			 setParameterToList(paralist, "TenGeNum", PARAMETER_TYPE_UINT8, &TenGeNum);
			 setParameterToList(paralist, "WifiNum", PARAMETER_TYPE_UINT8, &WifiNum);
			 setParameterToList(paralist, "UsbNum", PARAMETER_TYPE_UINT8, &UsbNum);
			 cmsXmlSetParameterByParaList(xmlShmCb, objOff, paralist);
			 freeParameterList(paralist);
		}
	}
	cmsXmlSetOneParameterByObjPath(xmlShmCb, "InternetGatewayDevice.DeviceInfo.", "X_CT-COM_DeviceType", PARAMETER_TYPE_UINT8, &deviceType);


	if(WifiNum == 0){
		int tmp_enable = FALSE;
		objData_wifi = cmsXml_GetObjectByOID(xmlShmCb, OID_InternetGatewayDevice_WiFi, 0, NULL_IF_NOT_EXISTED); 
		if(objData_wifi != NULL){
			objOff = cmsXmlGetPtrOffset(xmlShmCb, objData_wifi);
			paralist = newParameterList();
			if (paralist != NULL) {
				 setParameterToList(paralist, "X_GC_Enable", PARAMETER_TYPE_BOOLEAN, &tmp_enable);
				 cmsXmlSetParameterByParaList(xmlShmCb, objOff, paralist);
				 freeParameterList(paralist);
			}
		}	
	}
}



#ifdef DBUS_OBJECT_NOTIFY
void dbusObjSubscribe(int numOfObj, uint32_t *objPtr)
{
	int objIndex = 0; 
	int objCnt = 0;
	int i = 0;
	char str[8] = {0};
	
	for(i = 0; i < numOfObj; i++){
		objIndex = (objCnt/50) + 1;
		cmsXmlAddObjByOID(xmlShmCb, OID_InternetGatewayDevice_X_GC_DBUS_i , cmsXmlConstructIAValue(1,"%d",objIndex), 0, NULL);

		memset(str, 0, 8);
		sprintf(str, "Obj%d", (i%50)+1);
		//CMS_LOG(LL_ERROR, "set obj param name %s, %d\n", str, pAction->event->eventId[i]);
		cmsXmlSetOneParameterByOID(xmlShmCb,  OID_InternetGatewayDevice_X_GC_DBUS_i , cmsXmlConstructIAValue(1,"%d",objIndex), str, PARAMETER_TYPE_SINT31 , &(objPtr[i]));
		objCnt++;
	}
}

int resetDbusObj(void)
{
	//void *object = NULL;
	//char *nodeAddr = NULL;
	//objectNode_t *node = NULL;
	//cmsoffset_t objOff = 0, nodeOffset = 0;
	char objPath[64] = {0};
	int i = 0;

	/*reset dbus object param value*/
	/*object = cmsXmlGetObjectByName(xmlShmCb, "InternetGatewayDevice.X_GC_DBUS");
	if(object != NULL){
		objOff = cmsXmlGetPtrOffset(xmlShmCb, object);
		cmsXmlObjectRestore(xmlShmCb, objOff);
	}else{
		CMS_LOG(LL_ERROR, "dbus objec reset fail, object is NULL.\n");
		return CMS_NOK;
	}*/

	for(i = 0; i < InternetGatewayDevice_X_GC_DBUS_i_Max; i++){
		memset(objPath, 0, 64);
		sprintf(objPath, "InternetGatewayDevice.X_GC_DBUS.%d", i+1);
		cmsXmlDelObjByPathName(xmlShmCb, objPath);
	}
	

	/*check register object num if is exceed dbus support, if exceed, need enlarge*/
	/*if(numOfObj != 0){
		nodeAddr = object -sizeof(cmsoffset_t)*2;
		nodeOffset = *((cmsoffset_t *)nodeAddr);
		node = (objectNode_t *)cmsXmlGetObjRealAddr(xmlShmCb, nodeOffset);

		if(node->meta_count < numOfObj){
			CMS_LOG(LL_ERROR, "dbus objec need enlarge obj param num, register obj num %d, current support max obj num in dbus Obj %d.\n",
				numOfObj, node->meta_count);
			XMLSHMDEINIT(xmlShmCb);
			return CMS_NOK;
		}
	}*/
	return CMS_OK;
}
#endif

/*Start:functions for cms Timer task*/
void cms_Tms_addMilliSeconds(cmsTimestamp *tms, uint32_t ms)
{
	uint32_t addSeconds;
	uint32_t addNano;

	addSeconds = ms / MSECS_IN_SEC;
	addNano = (ms % MSECS_IN_SEC) * NSECS_IN_MSEC;

	tms->sec += addSeconds;
	tms->nsec += addNano;

	if (tms->nsec > NSECS_IN_SEC)
	{
		tms->sec++;
		tms->nsec -= NSECS_IN_SEC;
	}

	return;
}

void *cms_Memset( void *p_mem_block, unsigned int value_to_set, unsigned int num)
{
	return memset(p_mem_block,value_to_set, num);
}

void *cms_Malloc(unsigned int size)
{
	void *p_mem_to_return;

	p_mem_to_return = (void *) malloc(size);
	if(NULL == p_mem_to_return) {
		//gdbus_log_error("gMalloc FAIL\n");
		return NULL;
	}
	cms_Memset(p_mem_to_return, 0, size);
	return p_mem_to_return;

}

void cms_Free(void *ptr)
{
	if(ptr!=NULL){
		free(ptr);
		ptr = NULL;
	}
}

int cms_Tmr_init(void **tmrHandle)
{
   int ret = 0;
   cmsTimerHandle *cmstmrHandle;
   (*tmrHandle) = cms_Malloc(sizeof(cmsTimerHandle));
   if ((*tmrHandle) == NULL){
      ret = -1;
      return ret;
   }
   cmstmrHandle = (cmsTimerHandle *)(*tmrHandle);
   pthread_mutex_init(&cmstmrHandle->tmr_mtx, NULL);
   cmstmrHandle->running = 1;
   return ret;
}

void cms_Tmr_cleanup(void **handle)
{
	cmsTimerHandle *tmrHandle;
	cmsTimerEvent *tmrEvent;

	tmrHandle = (cmsTimerHandle *)handle;

	if(tmrHandle == NULL){
		return;
	}
	
	pthread_mutex_lock(&tmrHandle->tmr_mtx);
	tmrHandle->running = 0;

	while ((tmrEvent = tmrHandle->events) != NULL)
	{
		tmrHandle->events = tmrEvent->next;
		cms_Free(tmrEvent);
	}
	
	pthread_mutex_unlock(&tmrHandle->tmr_mtx);

	pthread_mutex_destroy(&tmrHandle->tmr_mtx);

	cms_Free((*handle));

	return;
}

int cms_Tmr_set(void *handle, cmsTimerEventHandler func, void *ctxData, uint32_t ms, const char *name)
{
	int ret = 0;
	cmsTimerHandle *tmrHandle;
	cmsTimerEvent *currEvent, *prevEvent, *newEvent;

	if (cms_Tmr_isEventPresent(handle, func, ctxData)==1){
		ret = -1;
		return ret;
	}

	if ((name != NULL) && (strlen(name) >= 64)){
		ret = -1;
		return ret;
	}

	newEvent = cms_Malloc(sizeof(cmsTimerEvent));
	if (newEvent == NULL){
		ret = -1;
		return ret;
	}

	newEvent->func = func;
	newEvent->ctxData = ctxData;

	cms_Tms_get(&(newEvent->expireTms));
	cms_Tms_addMilliSeconds(&(newEvent->expireTms), ms);

	if (name != NULL){
		sprintf(newEvent->name, "%s", name);
	}
	 
	tmrHandle = (cmsTimerHandle *) handle;
	 
	if(tmrHandle == NULL){
		ret = -1;
		return ret;
	}
	
	pthread_mutex_lock(&tmrHandle->tmr_mtx);
	 
	if (tmrHandle->eNumber == 0){
		tmrHandle->events = newEvent;
	}else{
		currEvent = tmrHandle->events;
		if(IS_EARLIER_THAN(&(newEvent->expireTms), &(currEvent->expireTms)))
		{
			newEvent->next = currEvent;
			tmrHandle->events = newEvent;
		}
		else
		{
			int done = 0;
			while (!done)
			{
				prevEvent = currEvent;
				currEvent = currEvent->next;

				if ((currEvent == NULL) ||(IS_EARLIER_THAN(&(newEvent->expireTms), &(currEvent->expireTms))))
				{
					newEvent->next = prevEvent->next;
					prevEvent->next = newEvent;
					done = 1;
				}
			}
		}
	}

	tmrHandle->eNumber++;

	pthread_mutex_unlock(&tmrHandle->tmr_mtx);

	return ret;
}  

void cms_Tmr_cancel(void *handle, cmsTimerEventHandler func, void *ctxData)
	{
	cmsTimerHandle *tmrHandle;
	cmsTimerEvent *currEvent, *prevEvent;

	tmrHandle = (cmsTimerHandle *) handle;
	
	if (tmrHandle == NULL || (currEvent = tmrHandle->events) == NULL)
	{
		return;
	}
	pthread_mutex_lock(&tmrHandle->tmr_mtx);

	if (currEvent->func == func && currEvent->ctxData == ctxData)
	{
		tmrHandle->events = currEvent->next;
		currEvent->next = NULL;
	}
	else
	{
		int done = 0;

		while ((currEvent != NULL) && (!done))
		{
			prevEvent = currEvent;
			currEvent = currEvent->next;

			if (currEvent != NULL && currEvent->func == func && currEvent->ctxData == ctxData)
			{
				prevEvent->next = currEvent->next;
				currEvent->next = NULL;
				done = 1;
			}
		}
	}

	if (currEvent != NULL)
	{
	  tmrHandle->eNumber--;
	}

	pthread_mutex_unlock(&tmrHandle->tmr_mtx);

	return;
}

int cms_Tmr_isEventPresent(const void *handle, cmsTimerEventHandler func, void *ctxData)
{
	cmsTimerHandle *tmrHandle;
	cmsTimerEvent *tmrEvent;
	int found=0;

	tmrHandle = (cmsTimerHandle *) handle;

	if(tmrHandle == NULL){
		return 0;
	}
	
	pthread_mutex_lock(&tmrHandle->tmr_mtx);

	tmrEvent = tmrHandle->events;

	while ((tmrEvent != NULL) && (!found))
	{
		if (tmrEvent->func == func && tmrEvent->ctxData == ctxData){
			found = 1;
		}else{
			tmrEvent = tmrEvent->next;
		}
	}

	pthread_mutex_unlock(&tmrHandle->tmr_mtx);

	return found;
}

void cms_oalTms_get(cmsTimestamp *tms)
{
   struct timespec ts;
   uint32_t rc;

   if (tms == NULL){
      return;
   }

   rc = clock_gettime(CLOCK_MONOTONIC, &ts);
   if (rc == 0){
      tms->sec = ts.tv_sec;
      tms->nsec = ts.tv_nsec;
   }else{
      tms->sec = 0;
      tms->nsec = 0;
   }
}

void cms_Tms_get(cmsTimestamp *tms)
{
   cms_oalTms_get(tms);
}

void cms_Tmr_executeExpiredEvents(void *handle)
{
	cmsTimerHandle *tmrHandle ;
	cmsTimerEvent *currEvent;
	cmsTimestamp nowTms;

	tmrHandle = (cmsTimerHandle *) handle;

	if(tmrHandle == NULL){
		return;
	}

	pthread_mutex_lock(&tmrHandle->tmr_mtx);

	cms_Tms_get(&nowTms);
	currEvent = tmrHandle->events;

	while ((currEvent != NULL) && (IS_EARLIER_THAN(&(currEvent->expireTms), &nowTms)))
	{
		tmrHandle->events = currEvent->next;
		currEvent->next = NULL;
		tmrHandle->eNumber--;

		pthread_mutex_unlock(&tmrHandle->tmr_mtx);

		(*currEvent->func)(currEvent->ctxData);

		cms_Free(currEvent);

		pthread_mutex_lock(&tmrHandle->tmr_mtx);

		currEvent = tmrHandle->events;
	}
	pthread_mutex_unlock(&tmrHandle->tmr_mtx);
   
	return;
}

void *cmsTaskTimerHandle(void *arg)
{
	cmsTimerHandle *tmrHandle;
	struct timeval t;
	signed long length = 0;

	tmrHandle = (cmsTimerHandle *)arg;

	while(tmrHandle->running){
		t.tv_sec = 1;
		t.tv_usec = 0;

		length = select(0, (fd_set*)NULL, (fd_set*)NULL, (fd_set*)NULL, &t);
		if(length < 0){
			continue;
		}
		cms_Tmr_executeExpiredEvents(tmrHandle);
	}

	return (void *)NULL;
}
/*End:functions for cms Timer task*/

void *getInternetWanPath(cmsXmlCb_t *xmlShmCb,char * objPathName)
{
	unsigned char wanPPPconnMax =0, wanIPconnMax =0;
	int WDev = 0, WCDev = 0, WANPPPDevice = 0, WANIPDevice = 0;
	void * object = NULL;
	
	cmsObj_InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANIPConnection_i_t *WANIPConnection_p = NULL;
	cmsObj_InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANPPPConnection_i_t *WANPPPConnection_p = NULL;
	wanPPPconnMax = InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANPPPConnection_i_Max;
	wanIPconnMax  =   InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANIPConnection_i_Max;
	WDev = 1;
	WCDev = 1;
	
	sprintf(objPathName, "InternetGatewayDevice.WANDevice.%d", WDev);
	object = cmsXml_GetObjectByName(xmlShmCb, objPathName, NULL_IF_NOT_EXISTED);
	if(!object)
		return NULL;
	sprintf(objPathName, "InternetGatewayDevice.WANDevice.1.WANConnectionDevice.%d", WCDev);
	object = cmsXml_GetObjectByName(xmlShmCb, objPathName, NULL_IF_NOT_EXISTED);
	if(!object)
		return NULL;
	
	
	for(WANPPPDevice = 1; WANPPPDevice <= wanPPPconnMax; WANPPPDevice++){
		sprintf(objPathName, "InternetGatewayDevice.WANDevice.%d.WANConnectionDevice.%d.WANPPPConnection.%d", WDev, WCDev,WANPPPDevice);
		object = cmsXml_GetObjectByName(xmlShmCb, objPathName, NULL_IF_NOT_EXISTED);
		if(object == NULL){
			continue;
		}
		WANPPPConnection_p = (cmsObj_InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANPPPConnection_i_t *)object;
		if(WANPPPConnection_p->Enable == 1 && strstr(WANPPPConnection_p->X_CT_COM_ServiceList,"INTERNET")){
			return (void *)WANPPPConnection_p;
		}
	
	}
	
	for(WANIPDevice = 1; WANIPDevice <= wanIPconnMax; WANIPDevice++){
		sprintf(objPathName, "InternetGatewayDevice.WANDevice.%d.WANConnectionDevice.%d.WANIPConnection.%d", WDev, WCDev,WANIPDevice);
		object = cmsXml_GetObjectByName(xmlShmCb, objPathName, NULL_IF_NOT_EXISTED);
		if(object == NULL){
			continue;
		}
		WANIPConnection_p = (cmsObj_InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANIPConnection_i_t *)object;
		if(WANIPConnection_p->Enable == 1 && strstr(WANIPConnection_p->X_CT_COM_ServiceList,"INTERNET")){
			return (void *)WANIPConnection_p;
		}
	
	}
	return NULL;
}

#if 0
/*Start:functions for cms task timer handle to do wan speed realtime Calculate*/
void systemCalculateWanSpeed()
{
	uint64_t up_bytes = 0;
	uint64_t down_bytes = 0;
	uint32_t upSpeed=0;
	uint32_t downSpeed=0;
	char ifName[32] = {0};
	int wanPhyType = 0;
	char wanPath[256] = {0};
	char wanStausPath[288] = {0};
	void *object = NULL;
	void *statsObject = NULL;
	uint32_t duration = 2;
	cmsObj_InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANPPPConnection_i_Stats_t *wanPPPStatus_p = NULL;
	cmsObj_InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANIPConnection_i_Stats_t *wanIPStatus_p = NULL;
	
	getDefaultWanStatus(xmlShmCb,&up_bytes,&down_bytes,ifName,&wanPhyType);

	if(up_bytes > preUpBytes){
		upSpeed = (up_bytes-preUpBytes)*8.0/1024/1024/duration;
	}

	if(down_bytes > preDownBytes){
		downSpeed = (down_bytes-preDownBytes)*8.0/1024/1024/duration;
	}
	
	preUpBytes = up_bytes;
	preDownBytes = down_bytes;

	if(wanPhyType == WAN_PHYTYPE_PON && strlen(ifName) > 0){
#ifdef GC_SUPPORT_ROUTER_FTTR
		getInternetWanPath(xmlShmCb,wanPath);
#else
		getObjectpathByIfname(xmlShmCb,wanPath,ifName);
#endif
	}

    if(wanPhyType == WAN_PHYTYPE_ETH){
        getInternetWanIntfName(xmlShmCb,ifName);
        if(strlen(ifName) > 0){
#ifdef GC_SUPPORT_ROUTER_FTTR
            getInternetWanPath(xmlShmCb,wanPath);
#else
            getObjectpathByIfname(xmlShmCb,wanPath,ifName);
#endif
        }
    }


	if(strlen(wanPath) > 0){
		object = cmsXml_GetObjectByName(xmlShmCb, wanPath, NULL_IF_NOT_EXISTED);
		if(object != NULL){
			sprintf(wanStausPath,"%s.Stats",wanPath);
			statsObject = cmsXml_GetObjectByName(xmlShmCb, wanStausPath, NULL_IF_NOT_EXISTED);
			if(statsObject != NULL){
				if(strstr(wanPath,"PPP")){
					wanPPPStatus_p = (cmsObj_InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANPPPConnection_i_Stats_t *)statsObject;
					wanPPPStatus_p->RealTime_Speed_UP = upSpeed;
					wanPPPStatus_p->RealTime_Speed_DOWN = downSpeed;
				}else{
					wanIPStatus_p = (cmsObj_InternetGatewayDevice_WANDevice_i_WANConnectionDevice_i_WANIPConnection_i_Stats_t *)statsObject;
					wanIPStatus_p->RealTime_Speed_UP = upSpeed;
					wanIPStatus_p->RealTime_Speed_DOWN = downSpeed;
				}
			}
		}
	}
	
	cms_Tmr_set(cmsTmrHandle, systemCalculateWanSpeed, NULL, duration*1000, "systemCalculateWanSpeed");	
}

void cmsTimerWanSpeedCountCalculateTask()
{		
	if (cms_Tmr_isEventPresent(cmsTmrHandle, systemCalculateWanSpeed, NULL)==1)
	{
		cms_Tmr_cancel(cmsTmrHandle, systemCalculateWanSpeed, NULL);
	}
	cms_Tmr_set(cmsTmrHandle, systemCalculateWanSpeed, NULL, 5000, "systemCalculateWanSpeed");	
}
/*End:functions for cms task timer handle to do wan speed realtime Calculate*/
#endif

void update_LANEthernetInterfaceConfig()
{
    //cmsTask_EthInfoUpdate();
    cms_Tmr_set(cmsTmrHandle, update_LANEthernetInterfaceConfig, NULL, 5000, "update_LANEthernetInterfaceConfig");
}

void cmsTimrLANEthernetInterfaceConfig()
{
    if (cms_Tmr_isEventPresent(cmsTmrHandle, update_LANEthernetInterfaceConfig, NULL) == 1) {
        cms_Tmr_cancel(cmsTmrHandle, update_LANEthernetInterfaceConfig, NULL);
    }
    cms_Tmr_set(cmsTmrHandle, update_LANEthernetInterfaceConfig, NULL, 5000, "update_LANEthernetInterfaceConfig");
}

void *cmsTaskTimerHandleLanHostSpeed(void *arg)
{
	cmsTimerHandle *tmrHandle;
	struct timeval t;
	signed long length = 0;

	tmrHandle = (cmsTimerHandle *)arg;

	while(tmrHandle->running){
		t.tv_sec = 1;
		t.tv_usec = 0;

		length = select(0, (fd_set*)NULL, (fd_set*)NULL, (fd_set*)NULL, &t);
		if(length < 0){
			continue;
		}
		cms_Tmr_executeExpiredEvents(cmsTmrHandleLanHostSpeed);
	}
	return (void *)NULL;
}

